{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Inception模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Inception(tf.keras.layers.Layer):\n",
    "    # 设置模块的构成\n",
    "    def __init__(self,c1,c2,c3,c4):\n",
    "        super().__init__()\n",
    "        # 线路1:1*1 RELU same c1\n",
    "        self.p1_1 = tf.keras.layers.Conv2D(c1,kernel_size=1,activation=\"relu\",padding =\"same\")\n",
    "        # 线路2:1*1 RELU same c2[0]\n",
    "        self.p2_1 = tf.keras.layers.Conv2D(c2[0],kernel_size=1,activation=\"relu\",padding=\"same\")\n",
    "        # 线路2:3*3 RELU same c2[1]\n",
    "        self.p2_2 = tf.keras.layers.Conv2D(c2[1],kernel_size=3,activation=\"relu\",padding='same')\n",
    "        # 线路3:1*1 RELU same c3[0]\n",
    "        self.p3_1 = tf.keras.layers.Conv2D(c3[0],kernel_size=1,activation=\"relu\",padding=\"same\")\n",
    "        # 线路3:5*5 RELU same c3[1]\n",
    "        self.p3_2 = tf.keras.layers.Conv2D(c3[1],kernel_size=5,activation=\"relu\",padding='same')\n",
    "        # 线路4: max-pool \n",
    "        self.p4_1 = tf.keras.layers.MaxPool2D(pool_size=3,padding=\"same\",strides=1)\n",
    "        # 线路4:1*1\n",
    "        self.p4_2 = tf.keras.layers.Conv2D(c4,kernel_size=1,activation=\"relu\",padding=\"same\")\n",
    "    # 前行传播过程\n",
    "    def call(self,x):\n",
    "        # 线路1\n",
    "        p1 = self.p1_1(x)\n",
    "        # 线路2\n",
    "        p2 = self.p2_2(self.p2_1(x))\n",
    "        # 线路3\n",
    "        p3 = self.p3_2(self.p3_1(x))\n",
    "        # 线路4\n",
    "        p4 = self.p4_2(self.p4_1(x))\n",
    "        # concat\n",
    "        outputs = tf.concat([p1,p2,p3,p4],axis=-1)\n",
    "        return outputs\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<__main__.Inception at 0x1048a6828>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Inception(64,(96,128),(16,32),32)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# GoogLeNet构建"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## B1模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "inputs = tf.keras.Input(shape=(224,224,1),name=\"input\")\n",
    "# 卷积:7*7 64 \n",
    "x = tf.keras.layers.Conv2D(64,kernel_size=7,strides = 2,padding=\"same\",activation=\"relu\")(inputs)\n",
    "# 池化层\n",
    "x = tf.keras.layers.MaxPool2D(pool_size=3,strides=2,padding=\"same\")(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## B2模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 卷积层:1*1\n",
    "x = tf.keras.layers.Conv2D(64,kernel_size = 1,padding='same',activation=\"relu\")(x)\n",
    "# 卷积:3*3\n",
    "x = tf.keras.layers.Conv2D(192,kernel_size=3,padding='same',activation='relu')(x)\n",
    "# 池化层\n",
    "x = tf.keras.layers.MaxPool2D(pool_size=3,strides=2,padding=\"same\")(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## B3模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# inception\n",
    "x = Inception(64,(96,128),(16,32),32)(x)\n",
    "# inception\n",
    "x = Inception(128,(128,192),(32,96),64)(x)\n",
    "# 池化\n",
    "x = tf.keras.layers.MaxPool2D(pool_size=3,strides=2,padding=\"same\")(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## B4模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 辅助分类器\n",
    "def aux_classifier(x,filter_size):\n",
    "    # 池化层\n",
    "    x = tf.keras.layers.AveragePooling2D(pool_size=5,strides = 3,padding='same')(x)\n",
    "    # 卷积层\n",
    "    x = tf.keras.layers.Conv2D(filters = filter_size[0],kernel_size=1,strides=1,padding =\"valid\",activation=\"relu\")(x)\n",
    "    # 展评\n",
    "    x = tf.keras.layers.Flatten()(x)\n",
    "    # 全连接\n",
    "    x = tf.keras.layers.Dense(units = filter_size[1],activation=\"relu\")(x)\n",
    "    # 输出层:\n",
    "    x = tf.keras.layers.Dense(units=10,activation=\"softmax\")(x)\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Inception\n",
    "x = Inception(192,(96,208),(16,48),64)(x)\n",
    "# 辅助输出\n",
    "aux_output1 = aux_classifier(x,[128,1024])\n",
    "# Inception\n",
    "x = Inception(160,(112,224),(24,64),64)(x)\n",
    "# Inception\n",
    "x = Inception(128,(128,256),(24,64),64)(x)\n",
    "# Inception\n",
    "x = Inception(112,(144,288),(32,64),64)(x)\n",
    "# 辅助输出2\n",
    "aux_output2 = aux_classifier(x,[128,1024])\n",
    "# Inception\n",
    "x =Inception(256,(160,320),(32,128),128)(x)\n",
    "# 最大池化\n",
    "x = tf.keras.layers.MaxPool2D(pool_size=3,strides=2,padding='same')(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## b5模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# inception\n",
    "x = Inception(256,(160,320),(32,128),128)(x)\n",
    "x = Inception(384,(192,384),(48,128),128)(x)\n",
    "# GAP\n",
    "x = tf.keras.layers.GlobalAvgPool2D()(x)\n",
    "# 输出层\n",
    "output = tf.keras.layers.Dense(10,activation=\"softmax\")(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 模型\n",
    "model = tf.keras.Model(inputs=inputs,outputs=[output,aux_output1,aux_output2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"functional_1\"\n",
      "__________________________________________________________________________________________________\n",
      "Layer (type)                    Output Shape         Param #     Connected to                     \n",
      "==================================================================================================\n",
      "input (InputLayer)              [(None, 224, 224, 1) 0                                            \n",
      "__________________________________________________________________________________________________\n",
      "conv2d_6 (Conv2D)               (None, 112, 112, 64) 3200        input[0][0]                      \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling2d_1 (MaxPooling2D)  (None, 56, 56, 64)   0           conv2d_6[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "conv2d_7 (Conv2D)               (None, 56, 56, 64)   4160        max_pooling2d_1[0][0]            \n",
      "__________________________________________________________________________________________________\n",
      "conv2d_8 (Conv2D)               (None, 56, 56, 192)  110784      conv2d_7[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling2d_2 (MaxPooling2D)  (None, 28, 28, 192)  0           conv2d_8[0][0]                   \n",
      "__________________________________________________________________________________________________\n",
      "inception_1 (Inception)         (None, 28, 28, 256)  163696      max_pooling2d_2[0][0]            \n",
      "__________________________________________________________________________________________________\n",
      "inception_2 (Inception)         (None, 28, 28, 480)  388736      inception_1[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling2d_5 (MaxPooling2D)  (None, 14, 14, 480)  0           inception_2[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "inception_3 (Inception)         (None, 14, 14, 512)  376176      max_pooling2d_5[0][0]            \n",
      "__________________________________________________________________________________________________\n",
      "inception_4 (Inception)         (None, 14, 14, 512)  449160      inception_3[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "inception_5 (Inception)         (None, 14, 14, 512)  510104      inception_4[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "inception_6 (Inception)         (None, 14, 14, 528)  605376      inception_5[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "inception_7 (Inception)         (None, 14, 14, 832)  868352      inception_6[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "max_pooling2d_11 (MaxPooling2D) (None, 7, 7, 832)    0           inception_7[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "average_pooling2d (AveragePooli (None, 5, 5, 512)    0           inception_3[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "average_pooling2d_1 (AveragePoo (None, 5, 5, 528)    0           inception_6[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "inception_8 (Inception)         (None, 7, 7, 832)    1043456     max_pooling2d_11[0][0]           \n",
      "__________________________________________________________________________________________________\n",
      "conv2d_27 (Conv2D)              (None, 5, 5, 128)    65664       average_pooling2d[0][0]          \n",
      "__________________________________________________________________________________________________\n",
      "conv2d_46 (Conv2D)              (None, 5, 5, 128)    67712       average_pooling2d_1[0][0]        \n",
      "__________________________________________________________________________________________________\n",
      "inception_9 (Inception)         (None, 7, 7, 1024)   1444080     inception_8[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "flatten (Flatten)               (None, 3200)         0           conv2d_27[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "flatten_1 (Flatten)             (None, 3200)         0           conv2d_46[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "global_average_pooling2d (Globa (None, 1024)         0           inception_9[0][0]                \n",
      "__________________________________________________________________________________________________\n",
      "dense (Dense)                   (None, 1024)         3277824     flatten[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dense_2 (Dense)                 (None, 1024)         3277824     flatten_1[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dense_4 (Dense)                 (None, 10)           10250       global_average_pooling2d[0][0]   \n",
      "__________________________________________________________________________________________________\n",
      "dense_1 (Dense)                 (None, 10)           10250       dense[0][0]                      \n",
      "__________________________________________________________________________________________________\n",
      "dense_3 (Dense)                 (None, 10)           10250       dense_2[0][0]                    \n",
      "==================================================================================================\n",
      "Total params: 12,687,054\n",
      "Trainable params: 12,687,054\n",
      "Non-trainable params: 0\n",
      "__________________________________________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "model.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 数据读取"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from tensorflow.keras.datasets import mnist\n",
    "# 获取手写数字数据集\n",
    "(train_images, train_labels), (test_images, test_labels) = mnist.load_data()\n",
    "# 训练集数据维度的调整：N H W C\n",
    "train_images = np.reshape(train_images,(train_images.shape[0],train_images.shape[1],train_images.shape[2],1))\n",
    "# 测试集数据维度的调整：N H W C\n",
    "test_images = np.reshape(test_images,(test_images.shape[0],test_images.shape[1],test_images.shape[2],1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义两个方法随机抽取部分样本演示\n",
    "# 获取训练集数据\n",
    "def get_train(size):\n",
    "    # 随机生成要抽样的样本的索引\n",
    "    index = np.random.randint(0, np.shape(train_images)[0], size)\n",
    "    # 将这些数据resize成22*227大小\n",
    "    resized_images = tf.image.resize_with_pad(train_images[index],224,224,)\n",
    "    # 返回抽取的\n",
    "    return resized_images.numpy(), train_labels[index]\n",
    "# 获取测试集数据 \n",
    "def get_test(size):\n",
    "    # 随机生成要抽样的样本的索引\n",
    "    index = np.random.randint(0, np.shape(test_images)[0], size)\n",
    "    # 将这些数据resize成224*224大小\n",
    "    resized_images = tf.image.resize_with_pad(test_images[index],224,224,)\n",
    "    # 返回抽样的测试样本\n",
    "    return resized_images.numpy(), test_labels[index]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 获取训练样本和测试样本\n",
    "train_images,train_labels = get_train(256)\n",
    "test_images,test_labels = get_test(128)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模型编译"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 指定优化器，损失函数和评价指标\n",
    "optimizer = tf.keras.optimizers.SGD(learning_rate=0.01, momentum=0.0)\n",
    "# 模型有3个输出，所以指定损失函数对应的权重系数\n",
    "model.compile(optimizer=optimizer,\n",
    "              loss='sparse_categorical_crossentropy',\n",
    "              metrics=['accuracy'],loss_weights=[1,0.3,0.3])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模型训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/3\n",
      "2/2 [==============================] - 7s 4s/step - loss: 5.0465 - dense_4_loss: 2.5478 - dense_1_loss: 5.5701 - dense_3_loss: 2.7589 - dense_4_accuracy: 0.1174 - dense_1_accuracy: 0.0696 - dense_3_accuracy: 0.0739 - val_loss: 3.8758 - val_dense_4_loss: 2.2874 - val_dense_1_loss: 2.9486 - val_dense_3_loss: 2.3461 - val_dense_4_accuracy: 0.1538 - val_dense_1_accuracy: 0.1154 - val_dense_3_accuracy: 0.0769\n",
      "Epoch 2/3\n",
      "2/2 [==============================] - 7s 3s/step - loss: 3.8362 - dense_4_loss: 2.3122 - dense_1_loss: 2.7749 - dense_3_loss: 2.3050 - dense_4_accuracy: 0.1087 - dense_1_accuracy: 0.1043 - dense_3_accuracy: 0.1000 - val_loss: 3.7066 - val_dense_4_loss: 2.3002 - val_dense_1_loss: 2.3821 - val_dense_3_loss: 2.3059 - val_dense_4_accuracy: 0.1154 - val_dense_1_accuracy: 0.0769 - val_dense_3_accuracy: 0.0385\n",
      "Epoch 3/3\n",
      "2/2 [==============================] - 8s 4s/step - loss: 3.6779 - dense_4_loss: 2.3000 - dense_1_loss: 2.3131 - dense_3_loss: 2.2799 - dense_4_accuracy: 0.1043 - dense_1_accuracy: 0.1522 - dense_3_accuracy: 0.1522 - val_loss: 3.6978 - val_dense_4_loss: 2.3022 - val_dense_1_loss: 2.3475 - val_dense_3_loss: 2.3045 - val_dense_4_accuracy: 0.1154 - val_dense_1_accuracy: 0.0769 - val_dense_3_accuracy: 0.0385\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x141bf7f60>"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 模型训练：指定训练数据，batchsize,epoch,验证集\n",
    "model.fit(train_images,train_labels,batch_size=128,epochs=3,verbose=1,validation_split=0.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模型评估"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4/4 [==============================] - 1s 325ms/step - loss: 3.6632 - dense_4_loss: 2.2931 - dense_1_loss: 2.2922 - dense_3_loss: 2.2749 - dense_4_accuracy: 0.1484 - dense_1_accuracy: 0.1719 - dense_3_accuracy: 0.1328\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[3.663177967071533,\n",
       " 2.2930545806884766,\n",
       " 2.2921969890594482,\n",
       " 2.274880886077881,\n",
       " 0.1484375,\n",
       " 0.171875,\n",
       " 0.1328125]"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 指定测试数据\n",
    "model.evaluate(test_images,test_labels,verbose=1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
